package org.asiainfo.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil;
import com.mybatisflex.core.query.QueryMethods;
import org.asiainfo.common.core.constant.CacheNames;
import org.asiainfo.common.core.exception.ServiceException;
import org.asiainfo.common.core.utils.StringUtils;
import org.asiainfo.common.core.utils.TreeBuildUtils;
import org.asiainfo.common.redis.utils.CacheUtils;
import org.asiainfo.system.domain.table.SysCategoryTableDef;
import org.asiainfo.system.domain.vo.SysCategoryVo;
import org.asiainfo.system.domain.bo.SysCategoryBo;
import org.asiainfo.system.domain.SysCategory;
import org.asiainfo.system.service.SysCategoryService;
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Service;
import org.asiainfo.common.core.utils.MapstructUtils;
import lombok.extern.slf4j.Slf4j;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.asiainfo.system.mapper.SysCategoryMapper;

import java.util.ArrayList;
import java.util.List;

/**
 * 分类字典(SysCategory)表服务实现类
 *
 * @author dotor-ww
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SysCategoryServiceImpl extends ServiceImpl<SysCategoryMapper, SysCategory> implements SysCategoryService {

    /**
     * 构建查询条件
     *
     * @param sysCategoryBo 筛选条件
     * @return 查询条件
     */
    private QueryWrapper buildQueryWrapper(SysCategoryBo sysCategoryBo) {
        QueryWrapper query = query();
        query.likeRight(SysCategory::getCategoryName, sysCategoryBo.getCategoryName(), StringUtils.isNotBlank(sysCategoryBo.getCategoryName()));
        query.eq(SysCategory::getCategoryCode, sysCategoryBo.getCategoryCode(), StringUtils.isNotBlank(sysCategoryBo.getCategoryCode()));
        return query;
    }

    /**
     * 查询
     *
     * @param sysCategoryBo 筛选条件
     * @return 查询结果
     */
    @Override
    public List<SysCategoryVo> queryList(SysCategoryBo sysCategoryBo) {
        QueryWrapper query = buildQueryWrapper(sysCategoryBo);
        return listAs(query, SysCategoryVo.class);
    }

    /**
     * 通过categoryId查询单条数据
     *
     * @param categoryId 主键
     * @return 实例对象
     */
    @Override
    public SysCategoryVo queryById(Long categoryId) {
        return getOneAs(query().eq(SysCategory::getCategoryId, categoryId), SysCategoryVo.class);
    }

    /**
     * 新增数据
     *
     * @param sysCategoryBo 实例对象
     * @return 实例对象
     */
    @CachePut(cacheNames = CacheNames.SYS_CATEGORY, key = "#sysCategoryBo.categoryCode")
    @Override
    public List<SysCategoryVo> insertByBo(SysCategoryBo sysCategoryBo) {
        SysCategory info = getOne(query().eq(SysCategory::getCategoryId, sysCategoryBo.getParentId()));
        SysCategory sysCategory = MapstructUtils.convert(sysCategoryBo, SysCategory.class);
        if (ObjectUtil.isNull(sysCategory)) {
            throw new ServiceException("分类字典对象不能为空");
        }
        if (ObjectUtil.isNull(info)) {
            sysCategory.setParentId(0L);
            sysCategory.setAncestors("0");
        }else {
            sysCategory.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + sysCategoryBo.getParentId());
        }
        if (save(sysCategory)) {
            return new ArrayList<>();
        }
        throw new ServiceException("插入操作失败");
    }

    /**
     * 修改数据
     *
     * @param sysCategoryBo 实例对象
     * @return 实例对象
     */
    @CachePut(cacheNames = CacheNames.SYS_CATEGORY, key = "#sysCategoryBo.categoryCode")
    @Override
    public Boolean updateByBo(SysCategoryBo sysCategoryBo) {
        SysCategory sysCategory = MapstructUtils.convert(sysCategoryBo, SysCategory.class);
        return updateById(sysCategory);
    }

    /**
     * 通过主键删除数据
     *
     * @param categoryId 主键
     * @return 是否成功
     */
    @Override
    public Boolean deleteWithValidById(Long categoryId) {
        SysCategory category = getById(categoryId);
        CacheUtils.evict(CacheNames.SYS_CATEGORY, category.getCategoryCode());
        return removeById(categoryId);
    }

    /**
     * 校验分类名称是否唯一
     *
     * @param sysCategoryBo 实例对象
     * @return 结果
     */
    @Override
    public Boolean checkCategoryCodeUnique(SysCategoryBo sysCategoryBo) {
        return exists(query()
            .eq(SysCategory::getCategoryCode, sysCategoryBo.getCategoryCode())
            .eq(SysCategory::getParentId, sysCategoryBo.getParentId())
            .ne(SysCategory::getCategoryId, sysCategoryBo.getCategoryId(), ObjectUtil.isNotNull(sysCategoryBo.getCategoryId())));
    }

    /**
     * 判断分类字典下是否有子节点
     *
     * @param categoryId 主键
     * @return 结果
     */
    @Override
    public Boolean hasChildByCategoryId(Long categoryId) {
        return exists(query().eq(SysCategory::getParentId, categoryId));
    }

    /**
     * 获取分类字典列表
     *
     * @param sysCategoryBo 实体
     * @return 列表
     */
    @Override
    public List<SysCategoryVo> selectCategoryList(SysCategoryBo sysCategoryBo) {
        QueryWrapper query = buildQueryWrapper(sysCategoryBo);
        if (StringUtils.isNotBlank(sysCategoryBo.getCategoryCode())) {
            SysCategory category = getOne(query);
            return queryChain().select(SysCategoryTableDef.SYS_CATEGORY.DEFAULT_COLUMNS)
                .where(QueryMethods.findInSet(QueryMethods.number(category.getCategoryId()), SysCategoryTableDef.SYS_CATEGORY.ANCESTORS).gt(0))
                .listAs(SysCategoryVo.class);
        }
        return queryList(sysCategoryBo);
    }

    /**
     * 获取分类字典树列表
     *
     * @param categoryVos 分类字典列表
     * @return 树结构
     */
    @Override
    public List<Tree<Long>> buildCategoryTreeSelect(List<SysCategoryVo> categoryVos) {
        if (CollUtil.isEmpty(categoryVos)) {
            return CollUtil.newArrayList();
        }
        return TreeBuildUtils.build(categoryVos, (category, tree) -> {
            tree.setId(category.getCategoryId());
            tree.setParentId(category.getParentId());
            tree.setName(category.getCategoryName());
        });
    }
}
